#ifndef _SATA_SSD_H
#define _SATA_SSD_H

#include <systemc.h>
#include "SSD_define.h"
#include "SATA_command.h"
#include "NAND_device_if.h"
#include "SDRAM_DDR_DP_device_if.h"
//#include "SRAM_controller.h"

//#define DEBUG_SATA_SSD
//#define DEBUG_SATA_SSD_SDRAM_CTRL

const unsigned MAX_BUFFER_SATA_SSD	= 16;

class SATA_SSD
	: public sc_module
	//, public SRAM_controller
{
public :
	sc_in_clk				SATA_CLK;
	sc_in_clk				DRAM_CLK;
	sc_in_clk				FLASH_CLK;
	sc_in<bool>				RSTn;

	sc_in<int>				HTx_Dword;
	sc_out<int>				HRx_Dword;

	sc_port<NAND_device_if, 1> NAND_port_1;
	sc_port<NAND_device_if, 1> NAND_port_2;
	sc_port<SDRAM_DDR_DP_device_if, 1> DRAM_port;

	char					FIS_type;

	unsigned int			Addr;
	unsigned int			Addr_init;
	unsigned int			transfer_cnt;
	unsigned int			iteration;
	unsigned int			crc_buffer_cnt;
	
	bool					HWRITE, HREAD;
	bool					BSY;

	unsigned int			transport_currentstate;
	unsigned int			command_currentstate;

	bool					RegDHFIS_req;
	bool					DMAACTFIS_req;
	bool					DataFIS_req;
	bool					DMASTUPFIS_req;
	bool					FIS_receipt;
	unsigned int			frame_receipt;
	bool					crc_buffer_full;
	bool					crc_buffer_empty;

	//RegH2D_FIS
	bool					C;
	unsigned char			Command;
	unsigned int			LBA;
	unsigned int			LBA_Extend;
	unsigned char			Sector_cnt;
	unsigned char			Control;

	// Reg D2H FIS
	unsigned int			Reg_DH0;
	unsigned int			Reg_DH1;
	unsigned int			Reg_DH2;
	unsigned int			Reg_DH3;
	unsigned int			Reg_DH4;
	unsigned char			Status;
	unsigned char			FIStype;
	unsigned char			Dev_Head;
	bool					ssd_interrupt;

	//WRITE DMA
	bool					rcv_data;
/*
	sc_in<bool>				R_nB;
	sc_out<bool>			REb;
	sc_out<bool>			WEb;
	sc_inout<unsigned char>	DATA_IO;
*/
	void
	Transport_FSM_process();

	void
	Command_FSM_process();

	SC_HAS_PROCESS(SATA_SSD);

	SATA_SSD(sc_module_name name_,
			 unsigned		SSD_DMA_PRD_start_addr_,
			 unsigned		Main_SSD_DMA_cmd_reg_start_addr_,
			 unsigned		Main_DMA_check_reg_start_addr_,
			 unsigned		System_type_,
			 unsigned		DRAM_rank_index_,
			 unsigned		DRAM_bank_index_,
			 unsigned		DRAM_row_index_,
			 unsigned		DRAM_col_index_);

	~SATA_SSD();

protected:
	unsigned		System_type;

	unsigned		SSD_DMA_PRD_start_addr;
	unsigned		SSD_DMA_PRD_start_addr_init;
	unsigned		Main_SSD_DMA_cmd_reg_start_addr;
	unsigned		Main_DMA_check_reg_start_addr;

	unsigned		DRAM_rank_index;
	unsigned		DRAM_bank_index;
	unsigned		DRAM_row_index;
	unsigned		DRAM_col_index;

	SDRAM_state_t	DRAM_curr_state;
	bool			DRAM_refresh_enable;

	unsigned		SSD_DMA_command;
	unsigned		SSD_DMA_sector_cnt;
	unsigned		SSD_DMA_LBA;
	unsigned		SSD_DMA_LBA_current;
	unsigned		SSD_DMA_PRD_length;

	unsigned		SSD_DMA_base_addr;
	unsigned		SSD_DMA_base_cnt;

	unsigned		SSD_write_end;
	unsigned		SSD_DMA_end;

	bool			SSD_DMA_commanded;
	bool			SSD_DMA_enable;
	sc_time			SSD_DMA_enable_time;
	bool			SSD_DMA_PRD_fetched;
	sc_time			SSD_DMA_PRD_fetched_time;
	bool			SSD_DMA_buffered;
	sc_time			SSD_DMA_buffered_time;

	unsigned		PRD_current;

	void
	DRAM_timing_control_action();

	void
	Cache_arbiter_action();

	bool			C_WRITE, C_READ;
	bool			flush_RD_FIFO;

	bool			DRAM_or_SSD;
	bool			SSD_Cache_WR_request;
	bool			SSD_Cache_RD_request;
	bool			DRAM_Cache_WR_request;
	bool			DRAM_Cache_RD_request;
	bool			SSD_Cache_finished;
	bool			DRAM_Cache_finished;

	unsigned		SSD_WR_FIFO[CRC_BUFFER];
	unsigned		SSD_WR_pOUT;
	unsigned		SSD_WR_pIN;

	unsigned		SSD_RD_FIFO[CRC_BUFFER];
	unsigned		SSD_RD_pOUT;
	unsigned		SSD_RD_pIN;

	unsigned		DMA_SSD_RD_Buffer[MAX_BUFFER_SATA_SSD][CRC_BUFFER];
	unsigned		DMA_SSD_RD_Buffer_pOUT;
	unsigned		DMA_SSD_RD_Buffer_pIN;

	unsigned		DRAM_WR_FIFO[CRC_BUFFER];
	unsigned		DRAM_WR_pOUT;
	unsigned		DRAM_WR_pIN;

	unsigned		DRAM_RD_FIFO[CRC_BUFFER];
	unsigned		DRAM_RD_pOUT;
	unsigned		DRAM_RD_pIN;

	unsigned		DMA_DRAM_RD_Buffer[MAX_BUFFER_SATA_SSD][CRC_BUFFER];
	unsigned		DMA_DRAM_RD_Buffer_pOUT;
	unsigned		DMA_DRAM_RD_Buffer_pIN;

	unsigned		CH1_Buffer[CRC_BUFFER];
	unsigned		CH1_Buffer_pOUT;
	unsigned		CH1_Buffer_pIN;

	unsigned		CH2_Buffer[CRC_BUFFER];
	unsigned		CH2_Buffer_pOUT;
	unsigned		CH2_Buffer_pIN;

	unsigned		SRAM_Array[CACHE_BUFFER];
	unsigned		decision[CACHE_BUFFER/CRC_BUFFER];

	unsigned		LBA_write;
	unsigned		LBA_read;
	unsigned		LBA_write_temp;
	unsigned		LBA_read_temp;

	// Delay buffer
	unsigned		WR_FIFO_temp;
	unsigned		RD_FIFO_temp;

	void
	FIFO_process();
	
	void
	Cache_process();
	
	const bool
	Cache_decision(unsigned	LBA_) const;

	bool			F_WRITE_1;
	bool			F_READ_1;
	bool			F_ERASE_1;
	bool			F_WRITE_2;
	bool			F_READ_2;
	bool			F_ERASE_2;

	FLASH_state_t	current_state_1;
	FLASH_state_t	current_state_2;

	unsigned		cmd_1;
	unsigned		cmd_2;
	unsigned		DATA_cnt_1;
	unsigned		DATA_cnt_2;
	unsigned		DATA_word_1;
	unsigned		DATA_word_2;
	bool			Confirm_commanded_1;
	bool			Confirm_commanded_2;
	bool			cache_buffer_read_1;
	bool			cache_buffer_read_2;
	
	unsigned int	PA, BA;
	unsigned char	col_addr0, col_addr1, row_addr0, row_addr1;
	unsigned char	STATUS_reg;

	void
	FLASH_addr_gen(unsigned	LBA_);

	void
	FLASHcontroller_process_1();

	void
	FLASHcontroller_process_2();
};



#endif